1 /*
2  * Hunt - a framework for web and console application based on Collie using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.view.parser;
13 
14 import std.stdio;
15 import std.conv;
16 import std.algorithm;
17 import std.variant;
18 import std.array;
19 import std.string;
20 import std.typetuple;
21 
22 import hunt.view;
23 
24 abstract class Expression
25 {
26 	public string Evaluate(ViewContext ctx = null);
27 }
28 class Constant : Expression
29 {
30 	public string value;
31 	public this(string value)
32 	{
33 		this.value = value;
34 	}
35 	override public string Evaluate(ViewContext ctx = null )
36 	{
37 		return " str ~= `" ~ value ~ "`;";
38 	}
39 }
40 
41 class VariableReference : Expression
42 {
43 	public string value;
44 	public this(string value)
45 	{
46 		this.value = value;
47 	}
48 	override public string Evaluate(ViewContext ctx = null)
49 	{
50 		return " str ~= std.conv.to!string(" ~ value ~ ");";
51 	}
52 }
53 class ExecuteBlock : Expression
54 {
55 	public string value;
56 	public this(string value)
57 	{
58 		this.value = value;
59 	}
60 	override public string Evaluate(ViewContext ctx = null)
61 	{
62 		return value;
63 	}
64 }
65 class Operation : Expression
66 {
67 	public Expression left;
68 	public Expression value;
69 	public Expression right;
70 	public this(Expression left,Expression value,Expression right)
71 	{
72 		this.left = left;
73 		this.value = value;
74 		this.right = right;
75 	}
76 	override public string Evaluate(ViewContext ctx = null)
77 	{  
78 		auto x = left.Evaluate(ctx);  
79 		auto y = right.Evaluate(ctx);  
80 		return x ~ value.Evaluate(ctx) ~ y;  
81 	}  
82 }
83 Expression strToTree(string str,int s,int t)
84 {
85 	if(s >= t)return new Constant(null);
86 
87 	bool findVar = false;
88 	bool findExe = false;
89 	int ves,vet;
90 	static import std.algorithm;
91 	for(int i = s;i<t;i++)
92 	{
93 		if((i+2 <= t) && canFind(["{{","{%"],str[i..i+2]))
94 		{
95 			ves = i;
96 			if(str[i+1] == '{') findVar = true;
97 			else findExe = true;
98 			for(int k = i;k<t;k++)
99 			{
100 				if(canFind(["}}","%}"],str[k..k+2]))
101 				{
102 					vet = k+2;
103 					break;
104 				}
105 			}
106 			break;
107 		}
108 	}
109 	if(ves==0 && !findVar && !findExe)return new Constant(str[s..t]);
110 	if(findVar && ves==s && vet==t)return new VariableReference(str[ves+2 .. vet-2]);
111 	if(findExe && ves==s && vet==t)return new ExecuteBlock(str[ves+2 .. vet-2]);
112 	if(str[ves .. ves+2] == "{%")
113 		return new Operation(strToTree(str,s,ves),new ExecuteBlock(str[ves+2 .. vet-2]),strToTree(str,vet,t));
114 	else 
115 		return new Operation(strToTree(str,s,ves),new VariableReference(str[ves+2 .. vet-2]),strToTree(str,vet,t));
116 }
117 
118 class Parser 
119 {
120 	public string str;
121 	public string FunHeader = `
122 		static string TempleFunc(ViewContext var,CompiledTemple* ct = null){
123 			static import std.conv;
124 			string render(string _view_file)(){
125 				return render_with!_view_file(var);
126 			}
127 			string render_with(string _view_file)(ViewContext var = null){
128 				auto r = display!(_view_file)();
129 				return r.toString(var);
130 			}
131 			string yield(){
132 				return ct.toString(var);
133 			}
134 			string str;
135 			with(var){
136 				`;
137 	public string FunFooter = `
138 			}
139 			return str;
140 		}`;
141 	public Expression stt = null;
142 	public ViewContext ctx = null;
143 	this(string str)
144 	{
145 		this.str = str;
146 		this.stt = strToTree(str,0,str.length.to!int);
147 	}
148 	override string toString()
149 	{
150 		return FunHeader ~ stt.Evaluate(ctx) ~ FunFooter;
151 	}
152 }
153 
154 unittest 
155 {
156 	auto p = new Parser(```{% import std.stdio; %}<div>{{value["name"]}}```);
157 	assert(p.stt.Evaluate() == " str ~= ``; import std.stdio;  str ~= `<div>`; str ~= std.conv.to!string(value[\"name\"]); str ~= ``;");
158 }